﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Security.Cryptography;

namespace IcqSharp
{
    public class AuthorizationFamilyHandler // : FamilyHandler
    {
        public static void Handle(MemoryStream stream, SNACHeader header)
        {
            switch (header.Subtype)
            {
                case (UInt16)AuthorizationFamilySubtype.Error:
                    HandleAuthError(stream, header); break;

                case (UInt16)AuthorizationFamilySubtype.AuthKey:
                    HandleAuthKey(stream, header); break;

                case (UInt16)AuthorizationFamilySubtype.LoginReply:
                    CloseChannelHandler.HandleLoginReply(stream); break;

                default:
                    // NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) -
                    // Unknown SNAC (Flags: %u, Ref: %u)", 
                    // ICQ_AUTHORIZATION_FAMILY, pSnacHeader->wSubtype, 
                    // pSnacHeader->wFlags, pSnacHeader->dwRef);
                    break;
            }
        }

        public static void HandleAuthError(MemoryStream stream, SNACHeader header)
        {
            //WORD wError;

            //if (wBufferLength >= 2)
            //    unpackWord(&pBuffer, &wError);
            //else
            //    wError = 0;

            //LogFamilyError(ICQ_AUTHORIZATION_FAMILY, wError);
        }
        public static void HandleAuthKey(MemoryStream stream, SNACHeader header)
        {
            Log.Write("Got  Authorization.AuthKey");

            // Received ICQ_SIGNON_AUTH_KEY

            if (stream.Available() < 2)
            {
                Debugger.Break(); return;
            }

            var key_len = stream.ReadUInt16();
            if (key_len == 0 || key_len > stream.Available())
            {
                Debugger.Break(); return;
            }

            var key = stream.ReadBytes(key_len);
            var hash = HashPassword(key, Session.Password);


            // Sending ICQ_SIGNON_LOGIN_REQUEST to login server

            var p = new Packet();
            p.WriteFNACHeader((UInt16)Family.Authorization,
                (UInt16)AuthorizationFamilySubtype.LoginRequest);

            // pack UIN
            p.Data.WriteTLV(0x0001, Session.LocalUIN.ToString().GetAsciiBytes());

            // pack MD5 auth hash
            p.Data.WriteTLV(0x0025, hash);

            // pack empty TLV(0x4C) - unknown
            p.Data.Write((UInt32)0x004C0000);

            // pack client identification details
            p.Data.WriteTLV(0x0003, ClientDescription.IdString.GetAsciiBytes());
            p.Data.WriteTLV(0x0017, ClientDescription.VersionMajor);
            p.Data.WriteTLV(0x0018, ClientDescription.VersionMinor);
            p.Data.WriteTLV(0x0019, ClientDescription.VersionLesser);
            p.Data.WriteTLV(0x001a, ClientDescription.VersionBuild);
            p.Data.WriteTLV(0x0016, ClientDescription.IdCode);
            p.Data.WriteTLV(0x0014, ClientDescription.Distribution);
            p.Data.WriteTLV(0x000f, ClientDescription.Language.GetAsciiBytes());
            p.Data.WriteTLV(0x000e, ClientDescription.Country.GetAsciiBytes());
            p.Data.WriteTLV(0x0094, (Byte)(Session.ConnectionLost ? 1 : 0));
            if (Session.UseSSL) p.Data.Write((UInt32)0x008C0000);
            p.Send();

            Log.Write("Sent Authorization.LoginRequest");
        }

        private static Byte[] HashPassword(Byte[] authkey, String password)
        {
            var md5 = new MD5CryptoServiceProvider();
            var stream = new MemoryStream();

            // 1) authorization-key
            stream.Write(authkey);

            // 2) md5(pass-8-bytes)
            var pass_bytes = password.GetAsciiBytes().Take(8).ToArray();
            stream.Write(md5.ComputeHash(pass_bytes));

            // 3) client-string
            stream.Write("AOL Instant Messenger (SM)".GetAsciiBytes());

            return md5.ComputeHash(stream.ToArray());
        }



    }
}
